import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { io, Socket } from 'socket.io-client';
import { ElectronService } from './electron.service';
import { environment } from '../../environments/environment';

export class ClientSession {
  sessionid: number;
  writable: boolean = false;
  socket: Socket;
  constructor(type, host, url) {
    this.sessionid = Math.random();
    if (url)
      this.socket = io(url);
    else
      this.socket = io();
    this.socket.on('connect', () => {
      this.socket.emit('start', type, host);
    }).on('opened', (data: any) => {
      this.opened.next(data);
      this.writable = true;
    }).on('output', (data: string) => {
      this.output.next(data);
    }).on('progress', (data: any) => {
      this.progress.next(data);
    }).on('error', (error: string) => {
      this.error.next(error);
    }).on('close', () => {
      this.closed.next();
    }).on('filechanged', (data) => {
      this.filechange.next(data);
    })
  }
  protected error = new Subject<string>()
  protected output = new Subject<any>()
  protected opened = new Subject<any>()
  protected closed = new Subject<void>()
  protected destroyed = new Subject<void>()
  protected progress = new Subject<void>()
  protected filechange = new Subject<void>()

  get error$(): Observable<string> { return this.error }
  get output$(): Observable<any> { return this.output }
  get opened$(): Observable<any> { return this.opened }
  get closed$(): Observable<void> { return this.closed }
  get destroyed$(): Observable<void> { return this.destroyed }
  get progress$(): Observable<void> { return this.progress }
  get filechange$(): Observable<void> { return this.filechange }

  resize(columns: number, rows: number): void {
    this.socket.emit('resize', columns, rows);

  }

  write(data: String): void {
    this.socket.emit('write', data);
  }

  kill(signal?: string): void {
    this.socket.emit('kill');
    this.socket.disconnect();
  }

  list(dir: string) {
    return new Promise((resolve) => {
      this.socket.emit('list', dir);
      this.socket.once('list', (files) => resolve(files));
    })
  }
  fileSync(dir: string) {
    this.socket.emit('fileSync', dir);
  }
  upload(localPath, remotePath, fileList) {
    return new Promise((resolve) => {
      this.socket.emit('upload', localPath, remotePath, fileList);
      this.socket.once('upload', () => resolve(null));
    })
  }
  download(localPath, remotePath, fileList) {
    return new Promise((resolve) => {
      this.socket.emit('download', localPath, remotePath, fileList);
      this.socket.once('download', () => resolve(null));
    })
  }
  rename(oldname, newname) {
    return new Promise((resolve) => {
      this.socket.emit('rename', oldname, newname);
      this.socket.once('rename', () => resolve(null));
    })
  }
  delete(remotePath, fileList) {
    return new Promise((resolve) => {
      this.socket.emit('delete', remotePath, fileList);
      this.socket.once('delete', () => resolve(null));
    })
  }
  mkdir(name) {
    return new Promise((resolve) => {
      this.socket.emit('mkdir', name);
      this.socket.once('mkdir', () => resolve(null));
    })
  }
  readFile(file) {
    return new Promise((resolve) => {
      this.socket.emit('readFile', file);
      this.socket.once('readFile', (data) => resolve(data));
    })
  }
  writeFile(file, data) {
    return new Promise((resolve) => {
      this.socket.emit('writeFile', file, data);
      this.socket.once('writeFile', () => resolve(null));
    })
  }
  forwardByWindows(host) {
    return new Promise((resolve) => {
      this.socket.emit('forward-by-windows', host);
      this.socket.once('forward-by-windows', (host) => resolve(host));
    })
  }
  getSysParam() {
    return new Promise((resolve) => {
      this.socket.emit('getSysParam');
      this.socket.once('getSysParam', (param) => resolve(param));
    })
  }
}
@Injectable({
  providedIn: 'root'
})
export class SessionService {
  localSession: ClientSession;
  url: string;
  constructor(electron: ElectronService) {
    this.url = null;
    if (environment.serve) {
      this.url = 'http://127.0.0.1:3000';
    } else if (electron.isElectron) {
      this.url = 'http://127.0.0.1:' + electron.getLocalPort();
    }
    this.localSession = new ClientSession('local-sftp', null, this.url);
  }
  newSession(type: string, host: any = null): ClientSession {
    return new ClientSession(type, host, this.url);
  }
}
